package cangyan.msgcenter.utils;

import java.lang.reflect.Method;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.math.NumberUtils;

import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;


/**
 * 数据库查询结果POJO转换
 * @author chenyl
 */
public class DbUtil{
	private static final char SEPARATOR = '_'; 
	
	public static Map<String,Object> toMap(Record r) throws Exception{
		if(r==null){
			return null;
		}
		Map<String,Object> map = new HashMap<String,Object>();
		String[] colNames = r.getColumnNames();
		int len = colNames.length;
		for(int i = 0; i < len; i++){
			Object obj  = r.get(colNames[i]);
			if(obj instanceof Date){
				obj = DateUtil.formatDate((Date)obj);
			}else if(obj instanceof Time){
				obj = DateUtil.formatDate(new Date((((Time)obj)).getTime()));
			}else if(obj instanceof Timestamp){
				obj = DateUtil.formatDate(new Date((((Timestamp)obj)).getTime()));
			}
			map.put(lineToCamel(colNames[i], false), obj);
		}
		return map;
	}
	
	public static <T> T toBean(Class<T> clazz,Record r) throws Exception{
		if(r==null){
			return null;
		}
		T t = clazz.newInstance();
		String[] colNames = r.getColumnNames();
		int len = colNames.length;
		Map<String,Method> mm = getSetMethod(clazz);
		for(int i = 0; i < len; i++){
			Method m = mm.get(lineToCamel(colNames[i], true));
			Class<?> type = m.getParameterTypes()[0];
			if(m!=null){
				Object obj = r.get(colNames[i]);
				if(type.getName().equals(Long.class.getName())){
					obj = NumberUtils.toLong((obj==null)?null:obj.toString());
				}
				else if(type.getName().equals(Integer.class.getName())){
					obj = NumberUtils.toInt((obj==null)?null:obj.toString());
				}
				else if(type.getName().equals(String.class.getName())){
					obj = (obj==null)?null:obj.toString();
				}
				else if(type.getName().equals(Date.class.getName())){
					if(obj != null){
						if(obj instanceof Date){
							
						}else if(obj instanceof Time){
							obj = new Date(((Time)obj).getTime());
						}else if(obj instanceof Timestamp){
							obj = new Date(((Timestamp)obj).getTime());
						}else{
							throw new Exception(obj.getClass().getName() + "转"+Date.class.getName()+"错误");
						}
					}
				}
				else if(type.getName().equals(Float.class.getName())){
					obj = NumberUtils.toFloat((obj==null)?null:obj.toString());
				}
				else if(type.getName().equals(Double.class.getName())){
					obj = NumberUtils.toDouble((obj==null)?null:obj.toString());
				}
				m.invoke(t, obj);
			}
		}
		return t;
	}
	
	public static <T> List<T> toList(Class<T> clazz,List<Record> lst) throws Exception{
		if(lst == null){
			return null;
		}
		List<T> list = new ArrayList<T>();
		Record r = null;
		for(int i = 0 ; i < lst.size(); i++){
			r = lst.get(i);
			T t = toBean(clazz, r);
			if(t==null){
				break;
			}
			list.add(t);
		}
		return list;
	}
	
	public static List<Map<String,Object>> toList(List<Record> lst) throws Exception{
		if(lst == null){
			return null;
		}
		List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
		Record r = null;
		for(int i = 0 ; i < lst.size(); i++){
			r = lst.get(i);
			Map<String,Object> m = toMap(r);
			if(m==null){
				break;
			}
			list.add(m);
		}
		return list;
	}
	
	private static Map<String,Method> getSetMethod(Class<?> clazz){
		Map<String,Method> map = new HashMap<String, Method>();
		Method[] array = clazz.getMethods();
		int len = array.length;
		for(int i =0 ; i < len; i++){
			Method m = array[i];
			if(m.getName().startsWith("set")&& m.getParameterTypes().length==1){
				map.put(m.getName().substring(3), m);
			}
		}
		return map;
	}

	/**
	 * 
	 * @param str
	 * @param firstUpperCase 第一个字母是否大写
	 * @return
	 */
	public static String lineToCamel(String str,boolean firstUpperCase){
		if(str==null || str.length() == 0){
			return str;
		}
		str = str.toLowerCase();
		int len = str.length();
		StringBuffer sb = new StringBuffer();
		boolean upperCase = firstUpperCase;
		for(int i = 0; i < len; i++){
			char c = str.charAt(i);
			if(c==SEPARATOR){
				upperCase = true;
				continue;
			}
			if(upperCase){
				sb.append(Character.toUpperCase(str.charAt(i)));
				upperCase = false;
			}else{
				sb.append(str.charAt(i));
			}
		}
		return sb.toString();
	}

	public static String camelToLine(String str) throws Exception{
		if(str==null || str.length() == 0){
			return str;
		}
		StringBuilder sb = new StringBuilder();  
		boolean nextIsUpperCase = false;  
		int len = str.length();
		for(int i = 0; i < len; i++){
			char c = str.charAt(i);
			if(i<len-1){
				nextIsUpperCase = Character.isUpperCase(str.charAt(i+1));
			}else{
				nextIsUpperCase = false;
			}
			if(Character.isLowerCase(c)&& nextIsUpperCase){
				if(i<len-1){
					sb.append(c).append(SEPARATOR).append(Character.toLowerCase(str.charAt(i+1)));
					i++;
				}else{
					sb.append(c).append(SEPARATOR);
				}
				
			}else if(Character.isUpperCase(c)&& !nextIsUpperCase && i > 0){
				sb.append(SEPARATOR).append(Character.toLowerCase(str.charAt(i)));
			}else{
				sb.append(Character.toLowerCase(c));
			}
			
		}
		return sb.toString();
	}
	
	public static <T> T findFirst(Class<T> clazz,String sql,Object... paras) throws Exception{
		Record r = Db.findFirst(sql, paras);
		return toBean(clazz, r);
	}
	
	public static <T> T findFirst(Class<T> clazz,String sql) throws Exception{
		Record r = Db.findFirst(sql);
		return toBean(clazz, r);
	}
	
	public static Map<String, Object> findFirst(String sql,Object... paras) throws Exception{
		Record r = Db.findFirst(sql, paras);
		return toMap(r);
	}
	
	public static Map<String, Object> findFirst(String sql) throws Exception{
		Record r = Db.findFirst(sql);
		return toMap(r);
	}
	
	public static <T> List<T> find(Class<T> clazz,String sql, Object... paras) throws Exception{
		List<Record> list = Db.find(sql,paras);
		return toList(clazz, list);
	}
	
	public static <T> List<T> find(Class<T> clazz,String sql) throws Exception{
		List<Record> list = Db.find(sql);
		return toList(clazz, list);
	}
	
	public static List<Map<String, Object>> find(String sql, Object... paras) throws Exception{
		List<Record> list = Db.find(sql,paras);
		return toList(list);
	}
	
	public static List<Map<String, Object>> find(String sql) throws Exception{
		List<Record> list = Db.find(sql);
		return toList(list);
	}
	
}
